﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace 经典推箱子
{
    /// <summary>
    /// 主窗体类
    /// </summary>
    public partial class MainForm : Form
    {
        /// <summary>
        /// 最多15行
        /// </summary>
        public const int ROW = 15;
        /// <summary>
        /// 最多15列
        /// </summary>
        public const int COL = 15;
        /// <summary>
        /// 用于简单显示地图
        /// </summary>
        public readonly Label[,] labels = new Label[ROW, COL];

        /// <summary>
        /// 关卡序号
        /// </summary>
        public int no = 1;

        /// <summary>
        /// 关卡
        /// </summary>
        public Level level;

        /// <summary>
        /// 构造函数
        /// </summary>
        public MainForm()
        {
            this.DoubleBuffered = true;
            InitializeComponent();
            this.Init();
        }

        /// <summary>
        /// 鼠标悬停时，显示提示信息
        /// 作用于所有菜单项
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ToolStripMenuItem_MouseHover(object sender, EventArgs e)
        {
            ToolStripMenuItem item = (ToolStripMenuItem)sender;
            toolTip.Show(item.ToolTipText, this.menuStrip, Control.MousePosition.X - this.Location.X, Control.MousePosition.Y - this.Location.Y - 20);
        }

        /// <summary>
        /// 初始化
        /// </summary>
        private void Init()
        {
            for (int i = 0; i < ROW; i++)
            {
                for (int j = 0; j < COL; j++)
                {
                    if (labels[i, j] == null)
                    {
                        labels[i, j] = new Label();
                    }
                    Label label = labels[i, j];
                    label.BorderStyle = BorderStyle.None;
                    label.ForeColor = Color.Black;
                    label.Visible = true;
                    label.AutoSize = false;
                    label.Size = new Size(30, 30);
                    label.Location = new Point(j * labels[i, j].Size.Width, i * labels[i, j].Size.Height);
                    label.BackColor = Color.Black;
                    label.TextAlign = ContentAlignment.MiddleCenter;
                    label.Font = new Font("楷体", 12f);
                    panel.Controls.Add(label);
                }
            }
        }

        /// <summary>
        /// 把关卡绘画进label控件数组中
        /// </summary>
        private void Draw()
        {
            //尽可能把关卡画到游戏屏幕中间
            int minX = this.level.Map.Min(item => item.X);
            int maxX = this.level.Map.Max(item => item.X);
            int minY = this.level.Map.Min(item => item.Y);
            int maxY = this.level.Map.Max(item => item.Y);

            int width = maxY - minY + 1;
            int height = maxX - minX + 1;

            int offsetX = (ROW - height) / 2;
            int offsetY = (COL - width) / 2;

            foreach (var item in this.level.Map)
            {
                Label label = labels[item.X + offsetX, item.Y + offsetY];
                label.Text = "";
                label.BorderStyle = BorderStyle.FixedSingle;
                switch (item.Type)
                {
                    case BlockType.空地:
                        label.BackColor = Color.Black;
                        label.Text = "";
                        break;
                    case BlockType.墙壁:
                        label.BackColor = Color.White;
                        label.Text = "墙";
                        break;
                    case BlockType.箱子:
                        label.BackColor = Color.Blue;
                        label.Text = "箱";
                        break;
                    case BlockType.目标:
                        label.BackColor = Color.Yellow;
                        label.Text = "〇";
                        break;
                    case BlockType.完成:
                        label.BackColor = Color.Green;
                        label.Text = "×";
                        break;
                    case BlockType.主角:
                    case BlockType.进标:
                        label.BackColor = Color.Red;
                        label.Text = "人";
                        break;
                }
            }
        }

        /// <summary>
        /// 加载关卡
        /// </summary>
        private void LoadLevel()
        {
            try
            {
                this.panel.Controls.Clear();
                this.Init();
                if (this.level == null)
                {
                    this.level = new Level();
                }
                this.level.Init(no);
                this.Draw();
                this.Text = $"经典推箱子第【{no}】关";
            }
            catch (Exception exception)
            {
                //如果第一关不存在，则创建第一关
                if (no == 1)
                {
                    List<Tuple<int, int, int>> tuples = new List<Tuple<int, int, int>>();
                    tuples.Add(new Tuple<int, int, int>(0, 2, 1));
                    tuples.Add(new Tuple<int, int, int>(0, 3, 1));
                    tuples.Add(new Tuple<int, int, int>(0, 4, 1));

                    tuples.Add(new Tuple<int, int, int>(1, 2, 1));
                    tuples.Add(new Tuple<int, int, int>(1, 3, 3));
                    tuples.Add(new Tuple<int, int, int>(1, 4, 1));

                    tuples.Add(new Tuple<int, int, int>(2, 2, 1));
                    tuples.Add(new Tuple<int, int, int>(2, 3, 0));
                    tuples.Add(new Tuple<int, int, int>(2, 4, 1));
                    tuples.Add(new Tuple<int, int, int>(2, 5, 1));
                    tuples.Add(new Tuple<int, int, int>(2, 6, 1));
                    tuples.Add(new Tuple<int, int, int>(2, 7, 1));

                    tuples.Add(new Tuple<int, int, int>(3, 0, 1));
                    tuples.Add(new Tuple<int, int, int>(3, 1, 1));
                    tuples.Add(new Tuple<int, int, int>(3, 2, 1));
                    tuples.Add(new Tuple<int, int, int>(3, 3, 2));
                    tuples.Add(new Tuple<int, int, int>(3, 4, 0));
                    tuples.Add(new Tuple<int, int, int>(3, 5, 2));
                    tuples.Add(new Tuple<int, int, int>(3, 6, 3));
                    tuples.Add(new Tuple<int, int, int>(3, 7, 1));

                    tuples.Add(new Tuple<int, int, int>(4, 0, 1));
                    tuples.Add(new Tuple<int, int, int>(4, 1, 3));
                    tuples.Add(new Tuple<int, int, int>(4, 2, 0));
                    tuples.Add(new Tuple<int, int, int>(4, 3, 2));
                    tuples.Add(new Tuple<int, int, int>(4, 4, 6));
                    tuples.Add(new Tuple<int, int, int>(4, 5, 1));
                    tuples.Add(new Tuple<int, int, int>(4, 6, 1));
                    tuples.Add(new Tuple<int, int, int>(4, 7, 1));

                    tuples.Add(new Tuple<int, int, int>(5, 0, 1));
                    tuples.Add(new Tuple<int, int, int>(5, 1, 1));
                    tuples.Add(new Tuple<int, int, int>(5, 2, 1));
                    tuples.Add(new Tuple<int, int, int>(5, 3, 1));
                    tuples.Add(new Tuple<int, int, int>(5, 4, 2));
                    tuples.Add(new Tuple<int, int, int>(5, 5, 1));

                    tuples.Add(new Tuple<int, int, int>(6, 3, 1));
                    tuples.Add(new Tuple<int, int, int>(6, 4, 3));
                    tuples.Add(new Tuple<int, int, int>(6, 5, 1));

                    tuples.Add(new Tuple<int, int, int>(7, 3, 1));
                    tuples.Add(new Tuple<int, int, int>(7, 4, 1));
                    tuples.Add(new Tuple<int, int, int>(7, 5, 1));

                    StringBuilder sb = new StringBuilder();
                    foreach (var tuple in tuples)
                    {
                        sb.Append(tuple.Item1);
                        sb.Append(',');
                        sb.Append(tuple.Item2);
                        sb.Append(',');
                        sb.Append(tuple.Item3);
                        sb.Append('\n');
                    }
                    //保存到Level文件夹中
                    File.WriteAllText($"Level/{no}.level", sb.ToString());
                    //重新加载此关卡
                    this.LoadLevel();
                }
                //否则提示用户程序异常
                else
                {
                    MessageBox.Show(exception.Message, "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    //继续往外抛
                    throw;
                }
            }
        }

        /// <summary>
        /// 窗体加载
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MainForm_Load(object sender, EventArgs e)
        {
            //加载关卡
            this.LoadLevel();
        }

        /// <summary>
        /// 处理用户按键
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MainForm_KeyDown(object sender, KeyEventArgs e)
        {
            bool flag = false;

            //没过关时才判断移动，过关后不允许移动
            if (!this.level.Success())
            {
                switch (e.KeyCode)
                {
                    case Keys.A:
                    case Keys.Left:
                        flag = level.Turn(TurnType.左);
                        break;
                    case Keys.W:
                    case Keys.Up:
                        flag = level.Turn(TurnType.上);
                        break;
                    case Keys.D:
                    case Keys.Right:
                        flag = level.Turn(TurnType.右);
                        break;
                    case Keys.S:
                    case Keys.Down:
                        flag = level.Turn(TurnType.下);
                        break;
                }
            }

            //移动成功时，重新显示地图
            if (flag)
            {
                this.Draw();
                //过关时，短暂延迟后发出通知
                if (this.level.Success())
                {
                    Task.Run(() =>
                    {
                        Thread.Sleep(200);
                        MessageBox.Show("过关啦", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    });
                }
            }
        }

        private void 重新开始ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.LoadLevel();
        }

        private void 撤销ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (this.level.Last())
            {
                this.Draw();
            }
        }

        private void 删关ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (this.no <= 50)
            {
                MessageBox.Show("自带关卡不能删除", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            if (MessageBox.Show($"是否删除关卡【{no}】?", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) != DialogResult.OK)
            {
                return;
            }

            try
            {
                File.Delete($"Level/{no}.level");
                //删除完毕后，所有后面的关卡往前移动
                DirectoryInfo directory = new DirectoryInfo($"Level");
                FileInfo[] files = directory.GetFiles();
                for (int i = no - 1; i < files.Length; i++)
                {
                    files[i].MoveTo($"Level/{i + 1}.level");
                }
                MessageBox.Show($"关卡【{no}】删除完毕", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                while (true)
                {
                    try
                    {
                        //可以加载出目前关卡时退出循环，否则no一直减小，反正到1的时候肯定就可以加载成功了
                        //因为本程序设定关卡【1】不可被删除
                        LoadLevel();
                        break;
                    }
                    catch
                    {
                        no -= 1;
                    }
                }
            }
            catch
            {
                MessageBox.Show($"关卡【{no}】不存在", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void 上关ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                this.no--;
                this.LoadLevel();
            }
            catch
            {
                this.no++;
                this.LoadLevel();
            }
        }

        private void 下关ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                this.no++;
                this.LoadLevel();
            }
            catch
            {
                this.no--;
                this.LoadLevel();
            }
        }

        private void 添加ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DirectoryInfo directory = new DirectoryInfo($"Level");
            AddForm addForm = new AddForm(directory.GetFiles().Count() + 1);
            addForm.ShowDialog();
        }

        private void 选关ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SelectForm form = new SelectForm(no);
            form.ShowDialog();
            try
            {
                if (this.no != SelectForm.no)
                {
                    this.no = SelectForm.no;
                }
                this.LoadLevel();
            }
            catch (Exception exception)
            {
                MessageBox.Show(exception.Message, "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
                this.no = 1;
                this.LoadLevel();
            }
        }

        private void 说明ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            MessageBox.Show("1.【WASD】或方向键可以控制主角移动\n2.主角具备推动箱子的功能\n3.尝试将所有的箱子推到目标点吧", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }
    }
}
